package com.mojo.elastic.controller;

import com.mojo.elastic.pojo.Bank;
import com.mojo.response.ResultListVO;
import org.elasticsearch.index.query.*;
import org.elasticsearch.search.fetch.subphase.highlight.HighlightBuilder;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.data.elasticsearch.core.ElasticsearchOperations;
import org.springframework.data.elasticsearch.core.SearchHit;
import org.springframework.data.elasticsearch.core.SearchHits;
import org.springframework.data.elasticsearch.core.query.NativeSearchQuery;
import org.springframework.data.elasticsearch.core.query.NativeSearchQueryBuilder;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * 普通查询：范围查询，通配符模糊查询
 *
 * @author <a href="mailto:mojo_jj@163.com">Mojo</a>
 */
@RestController
public class CommonSearchController {
    private static final Logger logger = LoggerFactory.getLogger(CommonSearchController.class);
    @Resource
    private ElasticsearchOperations elasticsearchOperations;

    /*范围查询*/
    @GetMapping("/range")
    public ResultListVO<Bank> range() {
        RangeQueryBuilder rangeQueryBuilder = QueryBuilders.rangeQuery("age").from("20", false).to(30);
        return getResultListVO(rangeQueryBuilder);
    }

    /*通配符模糊查询*/
    @GetMapping("wildcard")
    public ResultListVO<Bank> wildcard() {
        WildcardQueryBuilder wildcardQueryBuilder = QueryBuilders.wildcardQuery("address.keyword", "*" + "*Bristol" +
                "*");
        return getResultListVO(wildcardQueryBuilder);

    }

    /*不适用通配符的模糊查询*/
    @GetMapping("/string_query")
    public ResultListVO<Bank> stringQuery() {
        QueryStringQueryBuilder stringQueryBuilder = QueryBuilders.queryStringQuery("Jefferson").field("address");
        return getResultListVO(stringQueryBuilder);
    }

    /*多字段查询*/
    @GetMapping("multi_query")
    public ResultListVO<Bank> multiMatchQuery() {
        Map<String, Float> fieldMap = new HashMap<>();
        fieldMap.put("lastname", 2f);
        MultiMatchQueryBuilder multiMatchQueryBuilder =
                QueryBuilders.multiMatchQuery("Harding", "firstname").fields(fieldMap);
        Map<String, Float> fields = multiMatchQueryBuilder.fields();
        logger.info("fields:{}", fields);
        return getResultListVO(multiMatchQueryBuilder);
    }

    private ResultListVO<Bank> getResultListVO(QueryBuilder wildcardQueryBuilder) {
        NativeSearchQueryBuilder queryBuilder = new NativeSearchQueryBuilder();
        queryBuilder.withQuery(wildcardQueryBuilder);
        queryBuilder.withHighlightBuilder(new HighlightBuilder().field("lastname").preTags("<span style='color:red" +
                "'>").postTags("</span>"));
        NativeSearchQuery query = queryBuilder.build();
        SearchHits<Bank> hits = elasticsearchOperations.search(query, Bank.class);
        List<Bank> list = new ArrayList<>(Math.toIntExact(hits.getTotalHits()));
        for (SearchHit<Bank> hit : hits) {
            highlightLastname(hit);
            list.add(hit.getContent());
        }
        return new ResultListVO<>(list);
    }

    private static void highlightLastname(SearchHit<Bank> hit) {
        List<String> lastname = hit.getHighlightField("lastname");
        hit.getContent().setFirstname(lastname.size() < 1 ? hit.getContent().getFirstname() :
                lastname.get(0));
    }
}
